package com.priox.sigar.jsf.util;


import com.mm.support.domain.TipoUsuario;
import com.mm.seguridad.dto.UsuarioDTO;
import com.mm.seguridad.service.MMAuthenticationToken;
import com.priox.sigar.domain.model.constantes.PathConstant;
import com.priox.sigar.server.infrastructure.persistence.exception.ApplicationException;
import com.priox.sigar.util.ExportUtil;
import com.priox.sigar.util.FileUtil;
import com.priox.sigar.util.MimeTypes;
import org.apache.commons.lang.StringUtils;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.treetable.TreeTable;
import org.primefaces.context.RequestContext;
import org.primefaces.event.CloseEvent;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;

import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;


public abstract class FindCrudBeanBase  {

    private static final Logger LOG = LoggerFactory.getLogger(FindCrudBeanBase.class);

    protected static final String SAME_PAGE = null;

    protected String noRecordFoundMsg = "label_no_records_found1";
    protected String noSelectedRowMsg = "noSelectedRowMsg";
    protected String successfullyUpdateMsg = "successfullyUpdateMsg";
    protected String successfullyDeleteMsg = "successfullyDeleteMsg";
    protected String invalidUploadedFile = "invalidUploadedFile";
    protected String successfullyUploadedMesg = "successfullyUploadedMesg";
    protected String successfullyCreatedMsg = "successfullyCreatedMsg";
    protected String invalidArgumentName = "invalidArgumentName";
    protected String needComment = "needComment";

    private String resourceBundleName = "messages";

    protected String flagTipoModal = "";

    private Long rowsPerPage = 25l;

    protected boolean persistMode = false;
    protected boolean updateMode = false;

    private String name = "";

    private UploadedFile file;

    private boolean noRecordFound = false;
    private boolean success = true;

    public abstract void setCursorTableNull();

    public abstract void onNewRecord(ActionEvent actionEvent);

    public abstract void onFind(ActionEvent actionEvent);

    public abstract void onClean(ActionEvent actionEvent);

    public abstract void onPersist(ActionEvent actionEvent);

    public abstract void onDelete(ActionEvent actionEvent);

    protected abstract void onDialogClose(CloseEvent event);

    public void initForm(ActionEvent actionEvent) {

    }

    public void printExcelReportAction(ActionEvent actionEvent) {
        String reportType = (String) actionEvent.getComponent().getAttributes().get("reportType");
        String templateFileName = (String) actionEvent.getComponent().getAttributes().get("templateFile");
        String templateType = (String) actionEvent.getComponent().getAttributes().get("templateType");
        try {
            final String PATH = PathConstant.DIR_JASPER;
            String jasper = PATH + File.separator + templateFileName;
            Map parameter = onPrintParameter(reportType,actionEvent);
            List registros = onRegistrosList(reportType,actionEvent);
            File baseFile = null;
            if ("pdf".equals(templateType)) {
                baseFile = ExportUtil.exportPdfToFile(jasper, parameter, registros, "report");
            } else {
                baseFile = ExportUtil.exportExcelToFile(jasper, parameter, registros, "report");
            }
            SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy-kkmmss");
            String filename = "report" + sdf.format(new Date()) + "." + templateType;
            exportFile(baseFile, filename);
        } catch (Exception e) {
            LOG.error("Error en el sistema ",e);
            addMessage(e.getMessage(), FacesMessage.SEVERITY_ERROR, e);
        }
    }

    protected List onRegistrosList(String templateFileName,ActionEvent actionEvent) {


        return null;
    }

    protected Map onPrintParameter(String templateFileName,ActionEvent actionEvent) {



        return null;
    }

    protected void exportFile(File file, String fileName) throws IOException {
        String type = fileName.substring(fileName.lastIndexOf(".") + 1);
        String contentType = MimeTypes.getMimeType(type);
        byte[] bytes = FileUtil.toByte(file);

        FacesContext facesContext = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
        response.reset();
        response.setContentType(contentType);
        response.setContentLength(bytes.length);
        response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "\"");
        response.setHeader("Cache-Control", "public");
        response.setHeader("Pragma", "public");
        response.setDateHeader("Expires", 0);

        ServletOutputStream ouputStream = response.getOutputStream();
        ouputStream.write(bytes, 0, bytes.length);
        ouputStream.flush();
        ouputStream.close();
        facesContext.responseComplete();
    }

    public String onDownloadFile(ActionEvent actionEvent) {
        return null;
    }

    public void cleanAction(ActionEvent actionEvent) {

        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot root = context.getViewRoot();
        resetDataTable(root);

        onClean(actionEvent);
        setCursorTableNull();
        resetForm(actionEvent.getComponent().getNamingContainer());
    }

    public void handleDialogClose(CloseEvent event) {


        LOG.debug("Handling dialog close in handleDialogClose()");
        onDialogClose(event);
        resetForm(event.getComponent());
    }

    public void handleDialogSelectClose(CloseEvent event) {

    }

    public void showNewDialog(ActionEvent actionEvent) {
        setFlagTipoModal((String) actionEvent.getComponent().getAttributes().get("flagTipoEncuesta"));
        onNewRecord(actionEvent);
        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");
        if(StringUtils.isNotBlank(dialogName)){
            executeModal(dialogName, true);
        }

    }

    public void selectAll(ActionEvent actionEvent) {

        onSelectAll(actionEvent);
    }

    protected void onSelectAll(ActionEvent actionEvent){

    }

    public void unSelectAll(ActionEvent actionEvent) {

        onUnSelectAll(actionEvent);
    }

    protected void onUnSelectAll(ActionEvent actionEvent){

    }


    public void showEditDialog(ActionEvent actionEvent) {

        String tableName = (String) actionEvent.getComponent().getAttributes().get("tableName");

        if (tableName != null && getSelectedRowTable(tableName) == null) {
            addMessage(noSelectedRowMsg, FacesMessage.SEVERITY_WARN);
        } else {
            onShowEditDialog(actionEvent);
            String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");
            executeModal(dialogName, true);
        }
        //return SAME_PAGE;
    }

    public void closeEditDialog(ActionEvent actionEvent) {
        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");
        if (dialogName != null) {
            executeModal(dialogName, false);
        }
        onFind(actionEvent);
    }

    public void showDeleteDialog(ActionEvent actionEvent) {

        String tableName = (String) actionEvent.getComponent().getAttributes().get("tableName");
        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");

        if (tableName != null && getSelectedRowTable(tableName) == null) {
            addMessage(noSelectedRowMsg, FacesMessage.SEVERITY_WARN);
        } else {
            executeModal(dialogName, true);
        }
    }

    public void showDeleteSelectDialog(ActionEvent actionEvent) {

        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");

        if (!isSelectRow()) {
            addMessage(noSelectedRowMsg, FacesMessage.SEVERITY_WARN);
        } else {
            executeModal(dialogName, true);
        }
    }

    public void showViewDialog(ActionEvent actionEvent) {

        String tableName = (String) actionEvent.getComponent().getAttributes().get("tableName");
        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");

        if (tableName != null && getSelectedRowTable(tableName) == null) {
            addMessage(noSelectedRowMsg, FacesMessage.SEVERITY_WARN);
        } else {
            onShowViewDialog(actionEvent);
            executeModal(dialogName, true);
        }
        //return SAME_PAGE;
    }



    public void onShowSaveDialog(ActionEvent actionEvent) {

    }

    public void onShowEditDialog(ActionEvent actionEvent) {

    }

    public void onShowViewDialog(ActionEvent actionEvent) {

    }


    //================================================================================
    // CRUD Action
    //================================================================================
    @Transactional
    public void findAction(ActionEvent actionEvent) {
        noRecordFound = false;
        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot root = context.getViewRoot();

        resetDataTable(root);

        setCursorTableNull();
        onFind(actionEvent);

        if (noRecordFound) {
            addMessage(noRecordFoundMsg, FacesMessage.SEVERITY_WARN);
        }

        //return SAME_PAGE;
    }

    @Transactional
    public void persistAction(ActionEvent actionEvent) {
        success = true;
        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");

        try {
            onPersist(actionEvent);
        } catch (ApplicationException e) {
            success = false;
            addMessage(e.getMessage(), FacesMessage.SEVERITY_WARN, e.getParameters());
        }
        if (success) {
            if (dialogName != null) {
                executeModal(dialogName, false);
            }
            addMessage(successfullyUpdateMsg);
            onFind(actionEvent);
        }
        //return SAME_PAGE;
    }

    @Transactional
    public void deleteAction(ActionEvent actionEvent) {
        success = true;
        onDelete(actionEvent);

        if (success) {
            addMessage(successfullyDeleteMsg);
            setCursorTableNull();
            onFind(actionEvent);
        }
        //return SAME_PAGE;
    }

    @Transactional
    public void deleteSelectAction(ActionEvent actionEvent) {
        success = true;
        onDeleteSelect(actionEvent);

        if (success) {
            addMessage(successfullyDeleteMsg);
            setCursorTableNull();
            onFind(actionEvent);
        }
        //return SAME_PAGE;
    }

    protected void onDeleteSelect(ActionEvent actionEvent){

    }


    public void onFileUpload(FileUploadEvent event) {

    }


    public void uploadFileAction(FileUploadEvent event) {
        success = true;
        file = event.getFile();
        if (file == null) {
            addMessage(invalidUploadedFile, FacesMessage.SEVERITY_ERROR);
            success = false;
        } else if ("".equals(file.getFileName())) {
            addMessage(invalidUploadedFile, FacesMessage.SEVERITY_WARN);
            success = false;
        } else if (file.getSize() == 0) {
            addMessage(invalidUploadedFile, FacesMessage.SEVERITY_WARN);
            success = false;
        } else if (!file.getFileName().endsWith(".csv") &&
                !file.getFileName().endsWith(".CSV")) {
            addMessage(invalidUploadedFile, FacesMessage.SEVERITY_WARN);
            success = false;
        }

        if (success) {
            try {
                onFileUpload(event);
            } catch (ApplicationException e) {
                LOG.error("error en el sistema ",e);
                success = false;
                addMessage(e.getMessage(), FacesMessage.SEVERITY_ERROR, e.getParameters());
            }
            if (success) {
                addMessage(successfullyUploadedMesg, FacesMessage.SEVERITY_INFO);
            }
        }

    }


    public void onPrint(ActionEvent actionEvent, List<String> columns, List<Map<String, String>> values) {

    }


    public UsuarioDTO getUser() {
        UsuarioDTO usuario = new UsuarioDTO();
        MMAuthenticationToken token = (MMAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        if(token.getToken()!=null){
            usuario.setNombreCompleto(usuario.getNombreCompleto());
            usuario.setTipoUsuario(TipoUsuario.INVITADO);
        }else{
            String username = (String) token.getPrincipal();
            usuario.setLogin(username);
            usuario.setUsuarioId((Long) token.getUsuarioId());
            usuario.setTipoUsuario((TipoUsuario) token.getRolId());
            usuario.setGrupoEmpresarialId((Long) token.getGrupoEmpresarialId());
        }
        return usuario;
    }

    protected void resetForm(UIComponent form) {

        for (UIComponent uic : form.getChildren()) {

            if (uic instanceof UIData) {
                UIData uiDataComponent = (UIData) uic;
                uiDataComponent.setRowIndex(-1);
            }

            if (uic instanceof EditableValueHolder) {
                EditableValueHolder evh = (EditableValueHolder) uic;
                evh.resetValue();
            }
            resetForm(uic);
        }
    }

    protected void resetDataTable(UIComponent uiComponent) {

        for (UIComponent uic : uiComponent.getChildren()) {

            if (uic instanceof DataTable) {
                DataTable dataTable = (DataTable) uic;
                dataTable.reset();
            }
            resetDataTable(uic);
        }
    }

    protected UIComponent findComponent(String id) {
        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot root = context.getViewRoot();

        return findComponent(root, id);
    }

    private UIComponent findComponent(UIComponent c, String id) {
        if (id.equals(c.getId())) {
            return c;
        }
        Iterator<UIComponent> kids = c.getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent found = findComponent(kids.next(), id);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    protected boolean isSelectRow(){
      return false;
    }


    protected Object getSelectedRowTable(String tableName) {
        Object selectedObject = null;
        UIComponent component = findComponent(tableName);
        String selectionMode = null;
        String selectionColMode = null;
        if (component instanceof DataTable) {
            DataTable dataTable = (DataTable) findComponent(tableName);
            selectedObject = dataTable.getSelection();
            selectionMode = dataTable.getSelectionMode();
            selectionColMode = dataTable.getColumnSelectionMode();
        } else if (component instanceof TreeTable) {
            TreeTable treeTable = (TreeTable) findComponent(tableName);
            selectedObject = treeTable.getSelection();
            selectionMode = treeTable.getSelectionMode();
        }
        if (("multiple".equals(selectionMode) || "multiple".equals(selectionColMode))
                && ((Object[]) selectedObject).length == 0) {
            return null;
        }

        return selectedObject;
    }

    //================================================================================
    // Accessors
    //================================================================================
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public boolean isSuccess() {
        return success;
    }

    protected void setSuccess(boolean success) {
        this.success = success;
    }


    protected ResourceBundle getResourceBundle() {

        FacesContext facesContext = FacesContext.getCurrentInstance();
        ResourceBundle bundle = facesContext.getApplication().
                getResourceBundle(facesContext, resourceBundleName);

        return bundle;
    }

    public void addMessage(String key, Object... parameters) {
        addMessage(key, null, parameters);
    }

    public void addMessage(String key, FacesMessage.Severity severity, Object... parameters) {
        FacesMessage facesMessage;


        String text = getMessage(key, parameters);
        if (severity == null) {
            facesMessage = new FacesMessage("", text);
        } else {
            facesMessage = new FacesMessage(severity, "", text);
        }
        FacesContext facesContext = FacesContext.getCurrentInstance();
        facesContext.addMessage(null, facesMessage);
    }

    protected String getMessage(String key, Object... parameters) {
        String text = null;
        try {
            text = getResourceBundle().getString(key);
        } catch (java.util.MissingResourceException e) {
            text = key;
        }


        if (parameters != null && parameters.length > 0) {
            MessageFormat messageFormat = new MessageFormat(text);
            text = messageFormat.format(parameters);
        }

        return text;
    }


    protected void executeModal(String dialogName, boolean show) {

        RequestContext context = RequestContext.getCurrentInstance();
        if (show) {
            context.execute(dialogName + ".show()");
        } else {
            context.execute(dialogName + ".hide()");
        }
    }

    protected void navigateTo(String url) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
        try {
            String page = request.getContextPath() + "/pages/" + url;
            FacesContext.getCurrentInstance().getExternalContext().redirect(page);
        } catch (IOException e) {
            throw new ApplicationException("Error General", e);
        }
    }



    public UploadedFile getFile() {
        return file;
    }

    public void setFile(UploadedFile file) {
        this.file = file;
    }

    public boolean isNoRecordFound() {
        return noRecordFound;
    }

    public void setNoRecordFound(boolean noRecordFound) {
        this.noRecordFound = noRecordFound;
    }

    public Long getRowsPerPage() {
        return rowsPerPage;
    }

    public void setRowsPerPage(Long rowsPerPage) {
        this.rowsPerPage = rowsPerPage;
    }

    public boolean isPersistMode() {
        return persistMode;
    }

    public void setPersistMode(boolean persistMode) {
        this.persistMode = persistMode;
    }

    public String getFlagTipoModal() {
        return flagTipoModal;
    }

    public void setFlagTipoModal(String flagTipoModal) {
        this.flagTipoModal = flagTipoModal;
    }

    public boolean isUpdateMode() {
        return updateMode;
    }

    public void setUpdateMode(boolean updateMode) {
        this.updateMode = updateMode;
    }
}
